/***************************************************************************\
 * The Mattise Kernel														*
 * Copyright 2007 Matthew Iselin											*
 * Licensed under the GPL													*
 *																			*
 * gui.cc																	*
 *																			*
 * The Mattise GUI, must be a process and not a direct call.				*
 *																			*
\***************************************************************************/

#include <system.h>
#include <memory.h>
#include <iostream>
#include <mouse.h>
#include <vga.h>
#include <task.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <winman.h>
#include <filesys.h>
#include <pm.h> 			// --kmcguire: 7/15/2007

// global VGA system
VGA vga( 0xE0000000 );

// can we enter the VGA mode yet?
volatile int caninit = 0;

// drawing mutex
bool DrawMutex;
	
// location of the cursor
volatile int cx,cy;

// size of the cursor
uint_t CursorSize[2] = { 11, 20 };

// gets the cursor (32x32, red is the color key)
uchar_t* GetCursor();

// the cursor
uchar_t* MyCursor;

// the background data
uchar_t* DesktopBG;

// what was behind the cursor
uint_t* CursorBack;
	
// do we need to blit the old data?
volatile bool blitold = false,hasinit = false;

// old cursor x and y
volatile uint_t oldcx = 0,oldcy = 0;

// the mouse handler
void MouseHandler()
{
	// init the mouse
	mouseInit();
	
	// set the mouse co-ordinates
	cx = 0; cy = 0;
	
	// is the mouse down or up?
	int mousedown[3] = { 0, 0, 0 }; // three buttons
	
	// good to go!
	caninit = 1;
	
	// mouse data storage
	MOUSEDATA md;
	
	// always check the mouse
	while( true )
	{
		// get the mouse position
		GetMouseData( &md );
		
		// handle the new offsets
		cx += ( md.xmove * 1 );
		cy += ( md.ymove * -1 );
		
		// check for an overflow
		if( cx >= 800 ) { cx = 799; };
		if( cy >= 600 ) { cy = 599; };
		if( cx <= 0 ) { cx = 0; };
		if( cy <= 0 ) { cy = 0; };
		
		// tell the window manager if he needs to know something
		if( md.MouseStatus.StatData.leftbut )
		{
			// mouse down, left
			mousedown[0] = 1;
			
			// tell the window manager
			winman_MouseDown( 0, cx, cy );
		}
		if( md.MouseStatus.StatData.midbut )
		{
			// mouse down, middle
			mousedown[1] = 1;
			
			// tell the window manager
			winman_MouseDown( 1, cx, cy );
		}
		if( md.MouseStatus.StatData.rightbut )
		{
			// mouse down, right
			mousedown[2] = 1;
			
			// tell the window manager
			winman_MouseDown( 2, cx, cy );
		}
		if( !md.MouseStatus.StatData.leftbut && mousedown[0] )
		{
			// mouse up, left
			mousedown[0] = 0;
		}
		if( !md.MouseStatus.StatData.midbut && mousedown[1] )
		{
			// mouse up, middle
			mousedown[1] = 0;
		}
		if( !md.MouseStatus.StatData.rightbut && mousedown[2] )
		{
			// mouse up, right
			mousedown[2] = 0;
		}
		if( md.xmove || md.ymove )
		{
			// mouse move
			
			// please, blit the old data now, and blit the cursor
			blitold = true;
		}
	}
}

// the 'main()' of the GUI
void GUI()
{
	// setup the drawing mutex
	NewMutex( &DrawMutex );
	
	// create the mouse handler task
	// (obsolete) CreateThread( (unsigned int) MouseHandler, 1024, "MouseHandler", 10 );
	sched_threadDescription td;
	memset(&td, 0, sizeof(td));
	
	td.entry = (ENTRYADDR)&MouseHandler;
	td.contextId = 0;
	td.processId = 0;
	td.priority = 0;
	td.ustack = pm_alloc() + 4096;
	td.kstack = pm_alloc() + 4096;
	td.cs = 0x08;
	td.ds = 0x10;
	td.eflags = SCHED_EFLAGS32;
	td.medaddr = 0;
	sched_create_thread(&td, 0);

	// wait for the mouse
	while( caninit == 0 );
	
	// load the lads bg!
	//FILE lads = fopen( "dr0/lads background.bmp", "r" );
	
	// buffer for the bitmap
	//DesktopBG = (uchar_t*) kmalloc( lads.size );
	
	// read it all in
	//fread( DesktopBG, 0, lads.size, lads );
	
	// close it
	//fclose( lads );
	
	kprintf( "[GUI ] Entering 800x600x32 mode... " );
	
	// enter 800x600x32 mode
	vga.EnterVGAMode( 800, 600, 32 );
	
	kprintf( "Done!\n" ); // never going to get seen
	
	// get the cursor
	MyCursor = (uchar_t*) GetCursor();
	
	// set the background to a nice blue color
	vga.SetBgColor( 0x245DDB );
	
	// initialize the window manager
	InitWinMan();

	for(;;);	

	// setup the cursor
	CursorBack = vga.DrawCursor( MyCursor, cx, cy, 32, 32 );
	
	// test out windows
	CreateWindow( 0, "Hello!", 50, 50, 200, 200, DefCallback );
	CreateWindow( 0, "Hi!", 100, 100, 400, 400, DefCallback );

	// loop forever
	while( true )
	{
		// handle painting
		winman_Repaint();
		
		// blit the old data
/*		if( blitold )
		{
			// draw the old data
			if( hasinit )
				vga.DrawBitmap( CursorBack, oldcx, oldcy, 32, 32 );
			else
				hasinit = true;
			
			// don't blit until we need to
			blitold = false;
		
			// draw the cursor now
			CursorBack = vga.DrawCursor( MyCursor, cx, cy, 32, 32 );
		
			// set the old position
			oldcx = cx; oldcy = cy;
		}*/
		
		// blit the double buffer
		vga.BlitToScreen();
	}
}
